Etude sur le jeu de données "Wine Quality"

Source : UCI Machine Learning Repository
P. Cortez, A. Cerdeira, F. Almeida, T. Matos and J. Reis. Modeling wine preferences by data mining from physicochemical properties. In Decision Support Systems, Elsevier, 47(4):547-553, 2009.

0- Bibliothèques python utilisé :

In [1]:
import pandas as pd
import numpy as np

def warn(*args, **kwargs):
    pass
import warnings
warnings.warn = warn

import matplotlib.pyplot as plt
plt.style.use('ggplot')

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

from sklearn.calibration import CalibratedClassifierCV
from sklearn.model_selection import GridSearchCV

from sklearn.ensemble import RandomForestClassifier

from sklearn import metrics
from sklearn.metrics import  accuracy_score
from sklearn.metrics import plot_confusion_matrix

from joblib import dump, load

1- Lecture et visualisation des données :

a- lecture des deux jeux de données :

In [2]:
redWine = pd.read_csv("./data/winequality-red.csv",sep=";")
whiteWine = pd.read_csv("./data/winequality-white.csv",sep=";")

b- visualisation du type de données et du nombre de valeurs manquantes :

  • Aucune valeur manquante n'est observée dans les deux jeux de données.
  • L'attribut cible est un nombre entier et les autres attributs sont réels.
In [3]:
redWine.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1599 entries, 0 to 1598
Data columns (total 12 columns):
fixed acidity           1599 non-null float64
volatile acidity        1599 non-null float64
citric acid             1599 non-null float64
residual sugar          1599 non-null float64
chlorides               1599 non-null float64
free sulfur dioxide     1599 non-null float64
total sulfur dioxide    1599 non-null float64
density                 1599 non-null float64
pH                      1599 non-null float64
sulphates               1599 non-null float64
alcohol                 1599 non-null float64
quality                 1599 non-null int64
dtypes: float64(11), int64(1)
memory usage: 150.0 KB
In [4]:
whiteWine.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4898 entries, 0 to 4897
Data columns (total 12 columns):
fixed acidity           4898 non-null float64
volatile acidity        4898 non-null float64
citric acid             4898 non-null float64
residual sugar          4898 non-null float64
chlorides               4898 non-null float64
free sulfur dioxide     4898 non-null float64
total sulfur dioxide    4898 non-null float64
density                 4898 non-null float64
pH                      4898 non-null float64
sulphates               4898 non-null float64
alcohol                 4898 non-null float64
quality                 4898 non-null int64
dtypes: float64(11), int64(1)
memory usage: 459.3 KB

c- résumé descriptif des données :

  • La varibale cible doit être une valeur compris entre [0 et 10]. Néanmoins, dans nos deux datasets elle est comprise entre [3 et 9] pour les vins rouges et [3 et 8] pour les blancs.
  • La majorité des vins (rouge ou blanc) ont une qualité supérieure à la moyenne (Quality median = 6).
In [5]:
redWine.describe()
Out[5]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality
count 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000 1599.000000
mean 8.319637 0.527821 0.270976 2.538806 0.087467 15.874922 46.467792 0.996747 3.311113 0.658149 10.422983 5.636023
std 1.741096 0.179060 0.194801 1.409928 0.047065 10.460157 32.895324 0.001887 0.154386 0.169507 1.065668 0.807569
min 4.600000 0.120000 0.000000 0.900000 0.012000 1.000000 6.000000 0.990070 2.740000 0.330000 8.400000 3.000000
25% 7.100000 0.390000 0.090000 1.900000 0.070000 7.000000 22.000000 0.995600 3.210000 0.550000 9.500000 5.000000
50% 7.900000 0.520000 0.260000 2.200000 0.079000 14.000000 38.000000 0.996750 3.310000 0.620000 10.200000 6.000000
75% 9.200000 0.640000 0.420000 2.600000 0.090000 21.000000 62.000000 0.997835 3.400000 0.730000 11.100000 6.000000
max 15.900000 1.580000 1.000000 15.500000 0.611000 72.000000 289.000000 1.003690 4.010000 2.000000 14.900000 8.000000
In [6]:
whiteWine.describe()
Out[6]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality
count 4898.000000 4898.000000 4898.000000 4898.000000 4898.000000 4898.000000 4898.000000 4898.000000 4898.000000 4898.000000 4898.000000 4898.000000
mean 6.854788 0.278241 0.334192 6.391415 0.045772 35.308085 138.360657 0.994027 3.188267 0.489847 10.514267 5.877909
std 0.843868 0.100795 0.121020 5.072058 0.021848 17.007137 42.498065 0.002991 0.151001 0.114126 1.230621 0.885639
min 3.800000 0.080000 0.000000 0.600000 0.009000 2.000000 9.000000 0.987110 2.720000 0.220000 8.000000 3.000000
25% 6.300000 0.210000 0.270000 1.700000 0.036000 23.000000 108.000000 0.991723 3.090000 0.410000 9.500000 5.000000
50% 6.800000 0.260000 0.320000 5.200000 0.043000 34.000000 134.000000 0.993740 3.180000 0.470000 10.400000 6.000000
75% 7.300000 0.320000 0.390000 9.900000 0.050000 46.000000 167.000000 0.996100 3.280000 0.550000 11.400000 6.000000
max 14.200000 1.100000 1.660000 65.800000 0.346000 289.000000 440.000000 1.038980 3.820000 1.080000 14.200000 9.000000

d - Proportion des données en fonction de la couleur du vin :

  • Le nombre d'observations correspondant à du vin blanc est presque trois fois plus élevé que celui correspondant à du vin rouge.
In [7]:
fig1, ax1 = plt.subplots(facecolor=(1, 1, 1),figsize=(20,5))
ax1.pie([redWine.size,whiteWine.size], labels=('Red', 'White'), autopct='%1.1f%%',shadow=True, startangle=90)
ax1.axis('equal') 
fig1.suptitle('Proportion des vins selon leur couleur', fontsize=16)
plt.show()

e - Répartition moyenne des notes en fonction de la couleur du vin :

  • Les vins blancs ont tendance à avoir des notes plus élevées que celles des vins rouges.
In [8]:
whiteWine["type"]="White" 
redWine["type"]="Red"
data = pd.concat([whiteWine,redWine],ignore_index=True)
data.insert(0,"count",1)
result = data[["quality","type","count"]].groupby(["quality","type"]).count()
result.reset_index(level=[0,1], inplace=True)
result=result.pivot("quality","type","count")
result["Red"] = result["Red"]/len(redWine)
result["White"] = result["White"]/len(whiteWine)
result.plot(kind='bar',figsize=(19.5,8),title= "Répartition moyenne des notes en fonction de la couleur du vin" )
plt.show()
whiteWine = whiteWine.drop(["type"],1)
redWine = redWine.drop(["type"],1)

2 - Répartition des données et détection des valeurs aberrantes :

Nous pouvons constater à travers les boîtes à moustache ci-dessous, qu'un grand nombre d'observations contiennent des valeurs aberrantes, qui peuvent faire référence à des erreurs dans les données ou à des cas spécifiques pouvant potentiellement biaiser notre modèle (elles peuvent également être dues au fait que l'ensemble de données soit petit et loin d'être exhaustive).

In [9]:
def showOutliers(white,red):
    plt.figure(figsize=(20,20))
    plt.suptitle('Boxplots de chaque feature mettant en évidence les valeurs aberrantes',fontsize=24)
    for i in range(0,len(white.columns)):
        plt.subplot(4,3,i+1)
        plt.boxplot([white.iloc[:,i],red.iloc[:,i]])
        plt.title(white.columns[i],fontsize=18)
showOutliers(whiteWine,redWine)
  • Identifier le nombre d'observations contenant les valeurs aberrantes précédemment observées en utilisant l'intervalle interquartile (IQR) (z-score peut également être utilisée):
In [10]:
def getOutliersIndex(dataframe):
    outliersIndex = set()
    dataframe.reset_index(inplace=True,drop=True)
    for i in range(0,len(dataframe.columns)):
        p25 = np.percentile(dataframe.iloc[:,i],25)
        p75 = np.percentile(dataframe.iloc[:,i],75)
        iqr = p75 - p25
        iqrXi = iqr*1.5
        for j, val in enumerate(dataframe.iloc[:,i]):
            if val < p25-iqrXi or val > p75 + iqrXi:
                outliersIndex.add(j)
    print("Nbr outliers : ",len(outliersIndex))
    return outliersIndex

def dropOutliers(dataframe):
    initialSize = len(dataframe)
    cleanedData = dataframe.drop(getOutliersIndex(dataframe))
    print(round((initialSize-len(cleanedData))*100/initialSize,1),"% of the lines will be deleted")
    return cleanedData
  • Nous constatons que la suppression des valeurs aberrantes entraînerait une perte considérable d'informations.
In [11]:
cleaningWhite = dropOutliers(whiteWine)
cleaningRed = dropOutliers(redWine)
Nbr outliers :  1044
21.3 % of the lines will be deleted
Nbr outliers :  420
26.3 % of the lines will be deleted
  • Nous constatons que la normalisation supprimera tous les vins dont la qualité est inférieure à 4 et supérieure à 7.
In [12]:
showOutliers(cleaningWhite,cleaningRed)

3- Sélection des attributs :

a- corrélation des données :

Les deux matrices de corrélation ci-dessous ne permettent pas de conclure à l'existence d'une très forte corrélation évidente entre :

  • deux variables explicatives pour n'en sélectionner qu'une seule.
  • une variable expliquée et une variable explicative qui démontre l'importance de cette dernière dans la prédiction.

Cependant, nous remarquons que la variable "alcohol" pourrait être la variable la plus importante pour la prédiction.

Nous pouvons observer à travers la matrice de corrélation ci-dessous (vins rouges):

  • les variables ["fixed acidity", "citric acid", "density"],["free sulfur dioxide", "total sulfur dioxide"] sont positivement corrélées.
  • les variables ["pH", "citric acid"], ["volatile acidity", "citric acid"], ["fixed acidity", "pH"] sont négativement corrélées.
In [13]:
corr = redWine.corr()
corr.style.background_gradient(cmap='coolwarm')
Out[13]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality
fixed acidity 1 -0.256131 0.671703 0.114777 0.0937052 -0.153794 -0.113181 0.668047 -0.682978 0.183006 -0.0616683 0.124052
volatile acidity -0.256131 1 -0.552496 0.00191788 0.0612978 -0.0105038 0.07647 0.0220262 0.234937 -0.260987 -0.202288 -0.390558
citric acid 0.671703 -0.552496 1 0.143577 0.203823 -0.0609781 0.035533 0.364947 -0.541904 0.31277 0.109903 0.226373
residual sugar 0.114777 0.00191788 0.143577 1 0.0556095 0.187049 0.203028 0.355283 -0.0856524 0.00552712 0.0420754 0.0137316
chlorides 0.0937052 0.0612978 0.203823 0.0556095 1 0.00556215 0.0474005 0.200632 -0.265026 0.37126 -0.221141 -0.128907
free sulfur dioxide -0.153794 -0.0105038 -0.0609781 0.187049 0.00556215 1 0.667666 -0.0219458 0.0703775 0.0516576 -0.0694084 -0.0506561
total sulfur dioxide -0.113181 0.07647 0.035533 0.203028 0.0474005 0.667666 1 0.0712695 -0.0664946 0.0429468 -0.205654 -0.1851
density 0.668047 0.0220262 0.364947 0.355283 0.200632 -0.0219458 0.0712695 1 -0.341699 0.148506 -0.49618 -0.174919
pH -0.682978 0.234937 -0.541904 -0.0856524 -0.265026 0.0703775 -0.0664946 -0.341699 1 -0.196648 0.205633 -0.0577314
sulphates 0.183006 -0.260987 0.31277 0.00552712 0.37126 0.0516576 0.0429468 0.148506 -0.196648 1 0.0935948 0.251397
alcohol -0.0616683 -0.202288 0.109903 0.0420754 -0.221141 -0.0694084 -0.205654 -0.49618 0.205633 0.0935948 1 0.476166
quality 0.124052 -0.390558 0.226373 0.0137316 -0.128907 -0.0506561 -0.1851 -0.174919 -0.0577314 0.251397 0.476166 1
In [14]:
corr = whiteWine.corr()
corr.style.background_gradient(cmap='coolwarm')
Out[14]:
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality
fixed acidity 1 -0.0226973 0.289181 0.0890207 0.0230856 -0.0493959 0.0910698 0.265331 -0.425858 -0.017143 -0.120881 -0.113663
volatile acidity -0.0226973 1 -0.149472 0.0642861 0.0705116 -0.0970119 0.0892605 0.0271138 -0.0319154 -0.0357281 0.0677179 -0.194723
citric acid 0.289181 -0.149472 1 0.0942116 0.114364 0.0940772 0.121131 0.149503 -0.163748 0.0623309 -0.0757287 -0.00920909
residual sugar 0.0890207 0.0642861 0.0942116 1 0.0886845 0.299098 0.401439 0.838966 -0.194133 -0.0266644 -0.450631 -0.0975768
chlorides 0.0230856 0.0705116 0.114364 0.0886845 1 0.101392 0.19891 0.257211 -0.0904395 0.0167629 -0.360189 -0.209934
free sulfur dioxide -0.0493959 -0.0970119 0.0940772 0.299098 0.101392 1 0.615501 0.29421 -0.000617796 0.0592172 -0.250104 0.00815807
total sulfur dioxide 0.0910698 0.0892605 0.121131 0.401439 0.19891 0.615501 1 0.529881 0.00232097 0.134562 -0.448892 -0.174737
density 0.265331 0.0271138 0.149503 0.838966 0.257211 0.29421 0.529881 1 -0.0935915 0.0744931 -0.780138 -0.307123
pH -0.425858 -0.0319154 -0.163748 -0.194133 -0.0904395 -0.000617796 0.00232097 -0.0935915 1 0.155951 0.121432 0.0994272
sulphates -0.017143 -0.0357281 0.0623309 -0.0266644 0.0167629 0.0592172 0.134562 0.0744931 0.155951 1 -0.0174328 0.0536779
alcohol -0.120881 0.0677179 -0.0757287 -0.450631 -0.360189 -0.250104 -0.448892 -0.780138 0.121432 -0.0174328 1 0.435575
quality -0.113663 -0.194723 -0.00920909 -0.0975768 -0.209934 0.00815807 -0.174737 -0.307123 0.0994272 0.0536779 0.435575 1

b- Influence des attributs sur la qualité du vin :

  • les attributs "citric acid", "sulphates", "alcool" ont une influence positive sur la qualité.
  • les attributs "volatile acidity", "chlorides" et "pH" ont une influence négative sur la qualité.
  • les attributs "residual sugar" et "dencity" ne semblent pas avoir une tendance apparente ou une grande variance, nous expérimenterons un modèle qui ne les prend pas en considération.
In [15]:
import plotly.graph_objects as go

dataMean=redWine.groupby("quality").mean()
dataMean.reset_index(level=0, inplace=True)

quality = dataMean.quality.to_list()
fig = go.Figure()
for i,colName in enumerate(dataMean.columns[1:]):
    if i ==0:
        fig.add_trace(go.Bar(y=quality,x=dataMean[colName].to_list(),orientation='h',name=colName))
    else:
        fig.add_trace(go.Bar(y=quality,x=dataMean[colName].to_list(),orientation='h',name=colName,visible='legendonly'))
fig.update_layout(barmode='group',title="Influence des attributs sur la qualité du vin",    xaxis_title="Active legend attribut(default = fixed acidity)",yaxis_title="Quality Wine")
fig.show()

4- Prédiction de la qualité du vin :

In [16]:
def trainAndEvaluate(model,dataSet,withOutliers=False,TargetClass="quality"):
    """
        Cette fonction permet de :
            - withOutliers = True --> Supprimer les valeurs aberrantes (IQR).
            - model = entraîner le modèle spécifié en paramètre.
            - évaluer le modèle en utilisant la métrique de précision et la matrice de confusion.
    """
    # séparer le jeu de données en variables explicatives et les variables expliquées.
    if withOutliers:
        X = dropOutliers(dataSet).drop(TargetClass, axis = 1)
        y = dropOutliers(dataSet)[TargetClass]
    else:
        X = dataSet.drop(TargetClass, axis = 1)
        y = dataSet[TargetClass]    
    # diviser le jeu de données en un jeu de formation et un jeu de test avec un échantillonnage stratifié pour garder la distribution initiale des classes 
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.20, random_state = 1996,stratify=y)
    # entrainer le modèle.
    model.fit(X_train, y_train)
    # prédiction du jeu de test
    y_pred = model.predict(X_test)
    # évaluation du modèle en utilisant la précision
    print("Accuracy_score :",accuracy_score(y_pred,y_test))
    # afficher la matrice de confusion
    disp = plot_confusion_matrix(model, X_test, y_test,cmap=plt.cm.Blues)
    disp.ax_.set_title("Confusion Matrix")
    plt.show()
    return model

A - Pour le vin blan :

  • Vin blanc sans élimination des valeurs aberrantes :

Nous observons clairement à travers la matrice de corrélation ci-dessous que les classes ne sont pas correctement distribuées.

La solution est de supprimer les classes ayant un nombre insignifiant d’échantillons et cela soit avec un lissage par intervalle ou via la suppression des valeurs aberrantes.

In [17]:
# choix des hyperparamètres avec une recherche par grille.
calibrated_forest = CalibratedClassifierCV(base_estimator=RandomForestClassifier(n_estimators=500,random_state=1996))
param_grid = {'base_estimator__n_estimators':[400,500,600]}
rfModel = GridSearchCV(calibrated_forest, param_grid, cv=5)
trainAndEvaluate(rfModel,whiteWine,TargetClass="quality")
print("best_score of cross validation", rfModel.best_score_)
print("the best number of trees ", rfModel.best_params_)
Accuracy_score : 0.7081632653061225
best_score of cross validation 0.6633480595303255
the best number of trees  {'base_estimator__n_estimators': 400}
  • Vin blanc avec élimination des valeurs aberrantes (cette solution est brutale car nous n'avons pas une qtt importante de données) :
In [18]:
rfModelWithOut = RandomForestClassifier(n_estimators=400, random_state=1996)
trainAndEvaluate(rfModelWithOut,whiteWine,withOutliers=True,TargetClass="quality")
Nbr outliers :  1044
21.3 % of the lines will be deleted
Nbr outliers :  1044
21.3 % of the lines will be deleted
Accuracy_score : 0.7133592736705577
Out[18]:
RandomForestClassifier(n_estimators=400, random_state=1996)
  • Vin blan lissage des classes :
In [19]:
def smoothingInterval(x):
    if x > 6:
        return 3
    elif x < 6:
        return 0
    return 2

whiteWineSmoothed = whiteWine.copy()
whiteWineSmoothed["quality"] = whiteWine["quality"].map(smoothingInterval)
In [20]:
white_RF_Model_Smoothed = RandomForestClassifier(n_estimators=400, random_state=1996)
trainAndEvaluate(white_RF_Model_Smoothed,whiteWineSmoothed,withOutliers=False,TargetClass="quality")
Accuracy_score : 0.7520408163265306
Out[20]:
RandomForestClassifier(n_estimators=400, random_state=1996)
  • Utiliser la forêt aléatoire pour la sélection des attributs :
In [21]:
varImportance = pd.DataFrame(white_RF_Model_Smoothed.feature_importances_.tolist(),index=whiteWineSmoothed.columns.to_list()[:-1],columns=["importance"])
varImportance.sort_values('importance')
Out[21]:
importance
fixed acidity 0.071906
sulphates 0.075673
citric acid 0.081598
pH 0.084594
residual sugar 0.085266
chlorides 0.085428
total sulfur dioxide 0.089266
free sulfur dioxide 0.095535
volatile acidity 0.099409
density 0.107279
alcohol 0.124046
  • expérimenter la suppression de l'attribut le moins informatif "fixed acidity":

    • la précision a légèrement diminué.
In [22]:
white_RF_Model_Smoothed_select = RandomForestClassifier(n_estimators=400, random_state=1996)
trainAndEvaluate(white_RF_Model_Smoothed_select,(whiteWineSmoothed.drop(["fixed acidity"], axis = 1)),TargetClass="quality")
Accuracy_score : 0.7479591836734694
Out[22]:
RandomForestClassifier(n_estimators=400, random_state=1996)
  • Comme il est difficile de faire une sélection manuelle des attributs, il serait intéressant de procéder à une ACP.
In [23]:
X = whiteWineSmoothed.drop(['quality'], axis = 1)
y = whiteWineSmoothed['quality']
# Normalisation des données
sc_x=StandardScaler()
X = sc_x.fit_transform(X)
# Choix du nombre idéal de dimensions à conserver
pca=PCA()
X_pca = pca.fit_transform(X)
plt.figure(figsize=(10,8))
plt.plot(np.cumsum(pca.explained_variance_ratio_), 'ro-')
plt.grid()
  • on constate que le nombre idéal d'attributs se situe entre 8 et 9, nous choisirons n_components = 8
In [24]:
# transformation des données avec l'acp
pca_new = PCA(n_components=8)
whitePCAData = (pd.DataFrame(pca_new.fit_transform(X))).join(pd.DataFrame(y,columns=["quality"]))
rf_PCA_Smooth_white = RandomForestClassifier(n_estimators=400, random_state=1996)
trainAndEvaluate(rf_PCA_Smooth_white,pd.DataFrame(whitePCAData),TargetClass="quality")
Accuracy_score : 0.7306122448979592
Out[24]:
RandomForestClassifier(n_estimators=400, random_state=1996)

b- Pour le vin rouge :

In [25]:
print("__________________________________Random Forest____________________________________________")
print("Choix des hyperparamètres (n_estimators)")
calibrated_forest = CalibratedClassifierCV(base_estimator=RandomForestClassifier(n_estimators=500,random_state=1996))
param_grid = {'base_estimator__n_estimators':[400,500,600]}
rfModel = GridSearchCV(calibrated_forest, param_grid, cv=5)
trainAndEvaluate(rfModel,redWine,TargetClass="quality")
print("best_score of cross validation", rfModel.best_score_)
print("the best number of trees ", rfModel.best_params_)
nbrtree = rfModel.best_params_["base_estimator__n_estimators"]
print("_______________________________________Remove Outliers_______________________________________")
rfModelWithOut = RandomForestClassifier(n_estimators=nbrtree, random_state=1996)
trainAndEvaluate(rfModelWithOut,redWine,withOutliers=True,TargetClass="quality")
print("_______________________________________Smoothing Classe_______________________________________")
redWineSmoothed = redWine.copy()
redWineSmoothed["quality"] = redWine["quality"].map(smoothingInterval)
red_RF_Model_Smoothed = RandomForestClassifier(n_estimators=nbrtree, random_state=1996)
trainAndEvaluate(red_RF_Model_Smoothed,redWineSmoothed,withOutliers=False,TargetClass="quality")
print("__________________________________________ACP________________________________________________")
X = redWineSmoothed.drop(['quality'], axis = 1)
y = redWineSmoothed['quality']
# Normalisation des données
sc_x=StandardScaler()
X = sc_x.fit_transform(X)
# Choix du nombre idéal de dimensions à conserver
pca=PCA()
X_pca = pca.fit_transform(X)
plt.figure(figsize=(10,8))
plt.plot(np.cumsum(pca.explained_variance_ratio_), 'ro-')
plt.grid()
# transformation des données avec l'acp
pca_new = PCA(n_components=8)
redPCAData = (pd.DataFrame(pca_new.fit_transform(X))).join(pd.DataFrame(y,columns=["quality"]))
rf_PCA_Smooth_red = RandomForestClassifier(n_estimators=nbrtree, random_state=1996)
trainAndEvaluate(rf_PCA_Smooth_red,pd.DataFrame(redPCAData),TargetClass="quality")
__________________________________Random Forest____________________________________________
Choix des hyperparamètres (n_estimators)
Accuracy_score : 0.73125
best_score of cross validation 0.687297794117647
the best number of trees  {'base_estimator__n_estimators': 400}
_______________________________________Remove Outliers_______________________________________
Nbr outliers :  420
26.3 % of the lines will be deleted
Nbr outliers :  420
26.3 % of the lines will be deleted
Accuracy_score : 0.6864406779661016
_______________________________________Smoothing Classe_______________________________________
Accuracy_score : 0.771875
__________________________________________ACP________________________________________________
Accuracy_score : 0.7625
Out[25]:
RandomForestClassifier(n_estimators=400, random_state=1996)

Les deux modèles pouvant être intégrés à la production sont :

J'ai choisi d'utiliser les deux modèles ci-dessous de manière à obtenir la plus grande précision.

Et ce, sans supprimer les valeurs aberrantes et sans effectuer une sélection d'attributs.

Car, malgré la possibile d'avoir une grande précision en réalisant cette série de prétriatements, nos modèles peuvent être sujets à un sur-apprentissage (faible en généralisation à cause de la taille infime de nos deux ensembles de données).

I- Modèle pour le vin blanc :

  • Accuracy_score : 0.752040
In [26]:
dump(white_RF_Model_Smoothed,"model/WhiteWineModel.pkl")
Out[26]:
['model/WhiteWineModel.pkl']

II- Modèle pour le vin rouge :

  • Accuracy_score : 0.771875
In [27]:
dump(red_RF_Model_Smoothed,"model/RedWineModel.pkl")
Out[27]:
['model/RedWineModel.pkl']

Perspectives :

Il est également intéressant de tester d'autres modèles d'apprentissage automatique basés sur des réseaux de neurones qui peuvent potentiellement avoir une meilleure précision.